package com.migrate.module.task;

import cn.hutool.core.date.DateTime;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.migrate.module.constants.Constants;
import com.migrate.module.domain.EtlProgress;
import com.migrate.module.domain.EtlStatistical;
import com.migrate.module.mapper.migrate.MigrateScrollMapper;
import com.migrate.module.migrate.MergeConfig;
import com.migrate.module.util.MigrateUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.lang.reflect.Method;

import com.migrate.module.util.DateUtils;

import java.math.BigDecimal;
import java.util.Date;
import java.util.HashMap;
import java.util.List;

/**
 * 处理关于 表的数据量统计缓存，避免获取同步进度的计算效率过低
 * 统计每天的订单表和订单详情表产生的数据量，用来快速的计算出迁移进度
 *
 * @author zhonghuashishan
 */
@Component
@Slf4j
public class CountCacheTask {

    /**
     * 存储本次迁移的表
     */
    private static final String STATISTICAL_KEY = "statisticalKey";

    @Resource
    private MigrateScrollMapper migrateScrollMapper;

//    @PostConstruct
    public void init(){
        countRefresh();
    }

    /**
     * 每小时执行一次同步
     */
    @Scheduled(cron = "0 0 0/1 * * ?")
    void countRefresh(){
       try {
           Constants.statisticalCountMap.clear();
           // 获取所有配置的需要同步的表
           List<String> filedKeyList = MergeConfig.getFiledKey(STATISTICAL_KEY);
           for (String fileKey:filedKeyList){
               log.info("开始同步："+fileKey+"的表数据");
               EtlStatistical etlStatistical = new EtlStatistical();
               etlStatistical.setLogicModel(fileKey);
               EtlStatistical etlStatistical1 = migrateScrollMapper.getMaxDateEtlStatistical(etlStatistical);
               // 验证单个表的数据明细是否已统计，如果未统计则默认从最小时间天数 开始统计，否则只更新最近2天的数据(防止跨天数据产生)
               if (ObjectUtils.isNotEmpty(etlStatistical1)){
                   //已统计的最大时间格式
                   Integer statisticalTime = etlStatistical1.getStatisticalTime();
                   Long distanceDays = DateUtils.getDistanceDays(String.valueOf(statisticalTime), DateUtils.format(new Date()) + "");
                   Date minDate = null;
                   if (distanceDays < 2){
                       // 更新最近15天的该表统计数量
                       minDate = DateUtils.addDays( -2);
                   } else {
                       minDate = DateUtils.parseStrToDate(String.valueOf(statisticalTime), DateUtils.DATE_FORMAT_YYYYMMDD);
                   }
                   saveStatistical(minDate,fileKey,false);
               } else {
                   // 先取最小的日期，然后以该日期，以天为单位开始统计
                   Date minDate = getMinDate(fileKey);
                   saveStatistical(minDate,fileKey,true);
               }
           }
       }catch (Exception e){
            e.printStackTrace();
       }
    }

    /**
     * 按天去计算出每天该表的实际数据量
     * @param minDate 开始计算的时间
     */
    private void saveStatistical(Date minDate,String fileKey,boolean isNew){
       try {
           int num = DateUtils.daysBetween(minDate, new Date());
           Object mapper =  MigrateUtil.getD1MapperByTableName(fileKey);

            for (int i=0;i<num;i++){
                Date startDate = DateUtils.addDays(minDate, i);
                Date endDate = DateUtils.addDays(minDate, i);
                log.info("开始统计：startDate=" + DateUtils.parseDateToStr(startDate, "yyyyMMdd") + ",endDate=" + DateUtils.parseDateToStr(endDate, "yyyyMMdd"));
                if (null != mapper) {
                    EtlProgress etlProgress = new EtlProgress();
                    etlProgress.setScrollTime(DateUtils.getStartTimeOfDate(startDate));
                    etlProgress.setScrollEndTime(DateUtils.getDayEndTime(endDate));
                    Method targetMethod = mapper.getClass().getDeclaredMethod("countOrderInfo", EtlProgress.class);
                    Object returnValue = targetMethod.invoke(mapper, etlProgress);
                    if (null != returnValue) {
                        Integer statisticalCount = (Integer)returnValue;
                        this.saveOrUpdateStatistical(fileKey, startDate, statisticalCount, isNew);
                    }
                }
            }
       }catch (Exception e){
           e.printStackTrace();
       }
    }

    /**
     * 新增或者保存
     * @param logicModel
     * @param statisticalTime
     */
    private void saveOrUpdateStatistical(String logicModel, Date statisticalTime, Integer statisticalCount,boolean isNew){
        EtlStatistical statistical = new EtlStatistical();
        statistical.setLogicModel(logicModel);
        statistical.setStatisticalTime(DateUtils.format(statisticalTime));
        statistical.setStatisticalCount(statisticalCount);
        if (isNew){
            statistical.setCreateTime(new DateTime());
            statistical.setUpdateTime(new DateTime());
            migrateScrollMapper.insertEtlStatistical(statistical);
        } else {
            EtlStatistical etlStatistical = migrateScrollMapper.getEtlStatistical(statistical);
            if (etlStatistical == null){
                statistical.setCreateTime(new DateTime());
                statistical.setUpdateTime(new DateTime());
                migrateScrollMapper.insertEtlStatistical(statistical);
            } else {
                etlStatistical.setUpdateTime(new DateTime());
                migrateScrollMapper.updateEtlStatistical(statistical);
            }
        }
    }

    /**
     *  获取当前表的默认最小更新时间的日期
     * @param tableName
     * @return
     */
    private Date getMinDate(String tableName){
        try {
            Object mapper =  MigrateUtil.getD1MapperByTableName(tableName);
            if (null != mapper){
                Method targetMethod = mapper.getClass().getDeclaredMethod("queryMinDate");

                Object returnValue = targetMethod.invoke(mapper);
                if (null != returnValue){
                    return  (Date)returnValue;
                }
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return null;
    }

}
